package web.pojo;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import lombok.experimental.Accessors;
import org.springframework.http.HttpStatus;

import java.io.Serializable;
import java.time.Instant;
import java.time.ZonedDateTime;

import static constant.DateTimeConstant.ASIA_SHANGHAI;
import static constant.DateTimeConstant.DATE_TIME_FORMAT;
import static java.lang.String.valueOf;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;

/**
 * Result 响应信息主体
 */
@Getter
@Setter
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Accessors(chain = true)
public class R<T> implements Serializable {
    private static final long serialVersionUID = -87405767566025147L;

    public static final String OK = valueOf(HttpStatus.OK.value());
    public static final String OK_REASON_PHRASE = HttpStatus.OK.getReasonPhrase();
    public static final String ERROR = valueOf(INTERNAL_SERVER_ERROR.value());
    public static final String ERROR_REASON_PHRASE = INTERNAL_SERVER_ERROR.getReasonPhrase();

    // 为 null 则不序列化
    @Schema(description = "数据")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    T data;

    @Schema(description = "状态码")
    String code;

    @Schema(description = "错误")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    String error;

    @Schema(description = "消息")
    @JsonInclude(JsonInclude.Include.NON_NULL)
    String message;

    // 通过这种方式获取的时间戳与北京时间相差 8 个时区，需要修正为北京时间
    // 源码 Instant.now() 使用 UTC 时间 Clock.systemUTC().instant()
    // Instant time = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));


    // jackson 序列化时会格式化为指定的格式和时区
    // LocalDate、LocalDateTime 的 now() 方法使用的是系统默认时区，不存在 Instant.now() 的时间问题
    @Schema(description = "当前时间")
    @Builder.Default // https://blog.csdn.net/f641385712/article/details/82081900
    @JsonFormat(pattern = DATE_TIME_FORMAT, timezone = ASIA_SHANGHAI)
    Instant time = ZonedDateTime.now().toInstant();

    public static <T> R<T> ok(T data) {
        return R.<T>builder().code(OK).message(OK_REASON_PHRASE).data(data).build();
    }

    public static R<Object> error() {
        return R.<Object>builder().code(ERROR).message(ERROR_REASON_PHRASE).build();
    }
}